package tests.model_tests;

import static org.junit.Assert.*;

import java.io.IOException;

import org.junit.*;

import application.models.datalayer.*;
import application.models.exceptions.InvalidAttributeException;
import application.models.exceptions.MissingDataException;
import application.models.models.CarModel;

/**
 * This class tests the DatabaseCommunicator interface
 * 
 * @author Morten F. Therkildsen & Philip J. Rasmussen
 */
public class DatabaseCommunicator_test {

	private DataLayerCommunicator dlComm_first;

	@Before
	public void setup(){

		dlComm_first = DatabaseCommunicator.getInstance();

	}

	@Test
	public void test_getInstance(){

		// Test that the same instance is returned
		DataLayerCommunicator dlComm_second = DatabaseCommunicator.getInstance();
		assertEquals(dlComm_first, dlComm_second);

	}

	@Test
	public void test_getDataSetDescription(){

		// Test that setName cannot be null
		try{
			dlComm_first.getDataSetDescription(null);

		}catch(NullPointerException e){
			// This is supposed to happen
		}catch(Exception e){ fail("NullPointerException wasn't thrown for null parameter.");			
		}

		// Test that setName cannot be empty
		try{
			dlComm_first.getDataSetDescription("");

		}catch(IllegalArgumentException e){
			// This is supposed to happen
		}catch(Exception e){ fail("IllegalArgumentException wasn't thrown for empty parameter.");
		}

		// Test that an IOException is thrown if the setName doesn't exist in the data layer
		try{
			dlComm_first.getDataSetDescription("test!");

		} catch(IOException e){
			// This is supposed to happen
		} catch(Exception e){ fail("IOException was thrown for non-existant set name.");
		}

		// Test that no exception is thrown if the setName exist in the data layer
		try{
			dlComm_first.getDataSetDescription("cars");

		} catch(Exception e){ fail("An exception was thrown even though set name exist in the data layer.");
		}
	}

	@Test
	public void test_readFromDataLayer(){

		// Test that setName cannot be null
		try{
			dlComm_first.readFromDataLayer(null, new DataCondition[0]);

		}catch(NullPointerException e){
			// This is supposed to happen
		}catch(Exception e){ fail("NullPointerException wasn't thrown for null set name.");			
		}

		// Test that setName cannot be empty
		try{
			dlComm_first.readFromDataLayer("", new DataCondition[0]);

		}catch(IllegalArgumentException e){
			// This is supposed to happen
		}catch(Exception e){ fail("IllegalArgumentException wasn't thrown for empty set name.");
		}

		// Test that condition can be null
		try{
			dlComm_first.readFromDataLayer("test!", null);

		}catch(NullPointerException e){ fail("NullPointerException thrown for null condition. (not supposed to happen)");
		}catch(Exception e){
			// Any other exception thrown is not relevant to this test case
		}

		// Test that an IOException is thrown if the setName doesn't exist in the data layer
		try{
			dlComm_first.readFromDataLayer("test!", null);

		} catch(IOException e){
			// This is supposed to happen
		} catch(Exception e){ fail("IOException was thrown for non-existant set name.");
		}

		// Test that no exception is thrown if the setName exist in the data layer
		try{
			dlComm_first.readFromDataLayer("cars", null);

		} catch(Exception e){ fail("An exception was thrown even though set name exist in the data layer.");
		}
	}

	@Test
	public void test_writeToDataLayer() throws InvalidAttributeException, MissingDataException {

		// create a model
		CarModel model = new CarModel();	

		// Set attributes
		for(Attribute attribute : model){

			Object value = null;

			if(attribute.getDataType().equalsIgnoreCase("TEXT")) value = "Test!";
			else if(attribute.getDataType().equalsIgnoreCase("INTEGER")) value = new Integer(0);
			else if(attribute.getDataType().equalsIgnoreCase("DATE")) value = new Date(0);
			else if(attribute.getDataType().equalsIgnoreCase("BOOLEAN")) value = new Boolean(true);

			model.setAttribute(attribute.getName(), value);
		}

		// Soon ready for the test...
		model.save();

		// Test that set name cannot be null
		try{

			dlComm_first.writeToDataLayer(null, new Attribute[0]);
		} catch(NullPointerException e){
			// This is supposed to happen
		}catch(Exception e){ fail("NullPointerException wasn't thrown for null set name.");
		}

		// Test that set name cannot be empty
		try{

			dlComm_first.writeToDataLayer("", new Attribute[0]);
		} catch(IllegalArgumentException e){
			// This is supposed to happen
		}catch(Exception e){ fail("IllegalArgumentException wasn't thrown for empty set name.");
		}

		// Test that attributes cannot be null
		try{

			dlComm_first.writeToDataLayer("test!", null);
		} catch(NullPointerException e){
			// This is supposed to happen
		}catch(Exception e){ fail("NullPointerException wasn't thrown for null attributes.");
		}

		// Test that IOException is thrown if the set name doesn't exist in the data layer
		try{

			dlComm_first.writeToDataLayer("test!", new Attribute[0]);
		} catch(IOException e){
			// This is supposed to happen
		}catch(Exception e){ fail("IOException wasn't thrown for set name that doesn't exist in the data layer.");
		}
		
		model.delete(); // delete the model from the data layer
	}


	@Test
	public void test_deleteFromDataLeyer() throws InvalidAttributeException, MissingDataException {

		// create a model
		CarModel model = new CarModel();	

		// Set attributes
		for(Attribute attribute : model){

			Object value = null;

			if(attribute.getDataType().equalsIgnoreCase("TEXT")) value = "Test!";
			else if(attribute.getDataType().equalsIgnoreCase("INTEGER")) value = new Integer(0);
			else if(attribute.getDataType().equalsIgnoreCase("DATE")) value = new Date(0);
			else if(attribute.getDataType().equalsIgnoreCase("BOOLEAN")) value = new Boolean(true);

			model.setAttribute(attribute.getName(), value);
		}

		// Soon ready for the test...
		model.save();

		DataCondition condition = new DataCondition("number_plate", Operator.EQUALS, "Test!"); 

		// Test that set name cannot be null
		try{

			dlComm_first.deleteFromDataLayer(null, new DataCondition[]{condition});
		} catch(NullPointerException e){
			// This is supposed to happen
		}catch(Exception e){ fail("NullPointerException wasn't thrown for null set name.");
		}

		// Test that set name cannot be empty
		try{

			dlComm_first.deleteFromDataLayer("", new DataCondition[]{condition});
		} catch(IllegalArgumentException e){
			// This is supposed to happen
		}catch(Exception e){ fail("IllegalArgumentException wasn't thrown for empty set name.");
		}

		// Test that IOException is thrown if set name doesn't exist
		try{

			dlComm_first.deleteFromDataLayer("test!", new DataCondition[]{condition});
		} catch(IOException e){
			// This is supposed to happen
		}catch(Exception e){ fail("IOException wasn't thrown for set name that doesn't exist in the data layer.");
		}

		model.delete(); // delete the model from the data layer
	}
}
